home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Netware Super Library
/
Netware Super Library.iso
/
pgm_tool
/
nwbcas
/
nwbcast.asm
< prev
next >
Wrap
Assembly Source File
|
1994-01-25
|
13KB
|
281 lines
;*****************************************************************************
; PROGRAM ----: NWBCAST.ASM, version 1.0
; AUTHOR -----: Kevin E. Saffer, 904-296-9000 Days EST, 262-1020 Evenings
; COPYRIGHT --: None, placed into the public domain
; CREATED ----: 1/22/1994 at 13:04
;*****************************************************************************
; Introduction:
; -------------
; Implements a software interrupt service routine for the Novell shell
; versions 3.01 and above. The interrupt handler will insert a programmer
; specified keystroke into the PC's keyboard buffer whenever a broadcast
; message is detected. The Clipper application may then handle this event
; by defining a SET KEY procedure tied to the keystroke specified in the
; install routine. The Clipper procedure may then use the NETTO functions
; to handle the incoming message.
;
; Warning: This routine installs a ISR (interrupt service routine) which
; MUST be removed before program exit by calling the uninstall
; function. Leaving the ISR active after program completion will
; cause the computer to transfer control to an incorrect address
; the next time a broadcast message is detected. This will most
; likely result in a locked up PC. A future version can be built
; as a small TSR loaded before the Clipper application. This will
; allow the routine to remain in memory even if the Clipper pgm
; crashes. An interface module will be linked into the Clipper
; application to communicate with the TSR. After this release is
; debugged, I'll get to work on the TSR version.
;
; Since an ISR is used, this module may never be overlayed. The ISR code
; must always be available to handle the interrupt, therefore this object
; file must be placed into the root portion of your link script. It will
; only increase the load size of the application by 700 bytes.
;
; Compatibility:
; --------------
; Netware shell versions 3.01 and above will issue an INT 2F whenever a
; broadcast message is waiting. For this reason, the latest shells must be
; used; they are available for downloading on the Compuserve NOVLIB forum.
;
; This routine will not work with the DOS extenders from CA or Blinker. The
; reason it will not work is that I have no idea how to switch these routines
; from segment addressing over to protected mode addressing. If anyone has
; this knowledge, please share it on the forum or call me directly.
;
; Usage Restrictions:
; -------------------
; Should you wish to shell out of the Clipper application, this routine must
; be shut down using NB_STOP() prior to running other programs. If left
; active, any broadcast message will cause the specified keystroke to be
; fed into the shelled program. Re-start the routine using NB_START() when
; the Clipper application regains control.
;
; Messages Must Be Allowed! (CASTON)
; ----------------------------------
; Before use, you should change the Netware shell's brodcast mode to 0 to
; allow normal broadcast message handling. This routine will then prevent
; the message from being displayed on the last display line. Use the NETTO
; function FN_SETBMOD( 0 ) to accomplish this, or ensure CASTON has been
; executed prior to loading your application.
;
; Compiling/Linking:
; ------------------
; Compile with MASM 5.1 or greater using "MASM nwbcast;"
; Link the resulting NWBCAST.OBJ into your application at the root level.
;
;*****************************************************************************
; Clipper callable function list:
;*****************************************************************************
;
; NB_START( <key> ) - installs the interrupt service routine with specified key
; NB_STOP() - removes the interrupt service routine
; NB_SERVER() - returns the connection ID of the server holding the last message
;
;*****************************************************************************
.RADIX 16 ; my family has 8 fingers per hand so we think in HEX! <g>
; declare callable routines as public
PUBLIC NB_START ; installation routine
PUBLIC NB_STOP ; uninstallation routine
PUBLIC NB_SERVER ; last message server connection number
; declare clipper parameter routines
EXTRN __PARC:FAR ; get character string, segment:offset in DX:AX
EXTRN __PARCLEN:FAR ; get length of a string parameter into ax
EXTRN __PARCSIZ:FAR ; get size of memory allocated for string parameter
EXTRN __PARDS:FAR ; get date string, segment:offset in DX:AX
EXTRN __PARINFA:FAR ; get size of array parameter or element type
EXTRN __PARINFO:FAR ; get number of parameters or type of one
EXTRN __PARL:FAR ; get logical, value in AX
EXTRN __PARND:FAR ; get numeric double, segment:offset in DX:AX
EXTRN __PARNI:FAR ; get numeric integer, value in AX
EXTRN __PARNL:FAR ; get numeric long, value in DX:AX
EXTRN __RETC:FAR ; return string, push seg:off onto stack
EXTRN __RETCLEN:FAR ; return string of x length, push seg:off:length
EXTRN __RETDS:FAR ; return date string, push seg:off onto stack
EXTRN __RETL:FAR ; return logical, push 1 register onto stack
EXTRN __RETND:FAR ; return double, push 4 registers onto stack
EXTRN __RETNI:FAR ; return integer, push 1 register onto stack
EXTRN __RETNL:FAR ; return long, push 2 registers onto stack
; define a keyboard buffer structure for the insertion routine
BIOS_DATA SEGMENT AT 40
ORG 1A
BUFFER_HEAD DW ? ; pointer to the keybord buffer head
BUFFER_TAIL DW ? ; pointer to the keyboard buffer tail
ORG 80
BUFFER_START DW ? ; starting keyboard buffer address
BUFFER_END DW ? ; ending keyboard buffer address
BIOS_DATA ENDS
; declare our code segment
CODE SEGMENT 'CODE'
ASSUME CS:CODE,DS:CODE ; inform MASM of our intentions
OLDINTSEG DW 0 ; old 2F vector segment
OLDINTOFF DW 0 ; old 2F vector offset
KEYCODE DW 1 ; keyboard scan code to be inserted (this is Ctrl-A)
SERVERID DW 0 ; server connection number
;*****************************************************************************
; NB_START() - interrupt service routine installation
;*****************************************************************************
NB_START PROC FAR
PUSH BP ; save vital registers
MOV BP,SP
PUSH DS
PUSH ES
MOV AX,1 ; retrieve the keycode to be used
PUSH AX
CALL __PARNI
MOV CS:KEYCODE,AX ; save it and restore the stack
POP AX
PUSH CS ; reset the data segment to point to our code segment
POP DS
CMP OLDINTSEG,0 ; check to see if the vector was already changed
JZ NB_START1 ; no, proceed with vector change
POP ES ; restore clipper registers
POP DS
POP BP
CLD ; reset the direction flag
RET ; return to clipper
NB_START1:
MOV AX,352F ; get interrupt vector 2F into ES:BX
INT 21 ; call dos
MOV OLDINTSEG,ES ; save the existing handler segment
MOV OLDINTOFF,BX ; save the existing handler offset
MOV WORD PTR [INTADDR+2],ES ; update ISR with existing segment
MOV WORD PTR [INTADDR],BX ; update ISR with existing offset
PUSH CS ; store the segment of new routine
POP DS ; and place it into DS
MOV DX,OFFSET NB_INT2F ; offset of the new routine to DX
MOV AX,252F ; set interrupt vector 2F from DS:DX
INT 21 ; call dos
POP ES ; restore clipper registers
POP DS
POP BP
CLD ; reset the direction flag
RET ; return to clipper
NB_START ENDP
;*****************************************************************************
; NB_STOP() - interrupt service routine uninstallation
;*****************************************************************************
NB_STOP PROC FAR
PUSH BP ; save vital registers
MOV BP,SP
PUSH DS
PUSH ES
PUSH CS ; reset the data segment to point to our code segment
POP DS
CMP OLDINTSEG,0 ; check to see if the vector had been changed
JZ NB_STOP2 ; no, return to clipper
MOV AX,OLDINTSEG ; retrieve old routine segment
MOV DX,OLDINTOFF ; retrieve old routine offset
PUSH AX ; store the segment of old routine
POP DS ; and place it into DS
MOV AX,252F ; set interrupt vector 2F from DS:DX
INT 21 ; call dos
MOV OLDINTSEG,0 ; clear the existing handler segment
MOV OLDINTOFF,0 ; clear the existing handler offset
NB_STOP2:
POP ES ; restore clipper registers
POP DS
POP BP
CLD ; reset the direction flag
RET ; return to clipper
NB_STOP ENDP
;*****************************************************************************
; NB_SERVER() - return the connection ID of the server holding the message
;*****************************************************************************
NB_SERVER PROC FAR
PUSH BP ; save vital registers
MOV BP,SP
PUSH DS
PUSH ES
MOV AX,CS:SERVERID ; retrieve the connection number
PUSH AX
CALL __RETNI
POP AX
POP ES ; restore clipper registers
POP DS
POP BP
CLD ; reset the direction flag
RET ; return to clipper
NB_SERVER ENDP
;*****************************************************************************
; NB_INT2F - interrupt service routine
;*****************************************************************************
NB_INT2F PROC NEAR
PUSHF ; save calller's flags for the original interrupt 2F
CMP AX,7A85 ; is a broadcast message is waiting?
JE NB_INT2F1 ; yes, take over the interrupt
JMP NB_INT2F4 ; no, transfer control to the original interrupt
NB_INT2F1:
PUSH AX ; save the registers used by this routine
PUSH BX
PUSH DX
PUSH DS
PUSH CS ; set DS to this segment
POP DS
CLD ; clear direction flag
MOV CS:SERVERID,CX ; save the server connection number for later
XOR CX,CX ; inform Netware we will handle the message
MOV BX,BIOS_DATA ; point ds to the bios data area
MOV DS,BX
ASSUME DS:BIOS_DATA ; inform MASM of the new data segment
CLI ; disable interrupts for buffer manipulation
MOV BX,BUFFER_TAIL ; get buffer tail address
MOV DX,BX ; transfer it to DX
ADD DX,2 ; calculate next buffer position
CMP DX,BUFFER_END ; did we overshoot the end?
JNE NB_INT2F2 ; no, then continue
MOV DX,BUFFER_START ; yes, then wrap to start of buffer
NB_INT2F2:
CMP DX,BUFFER_HEAD ; is the buffer full?
JE NB_INT2F3 ; yes, then end now
MOV AX,CS:KEYCODE ; retrieve the keycode
MOV [BX],AX ; insert the keycode into the keyboard buffer
MOV BX,DX ; advance the tail
MOV BUFFER_TAIL,BX ; record its new position
NB_INT2F3:
STI ; enable interrupts
POP DS ; restore registers
POP DX
POP BX
POP AX
NB_INT2F4:
POPF ; restore the caller's flags
DB 0EAH ; JMP FAR immediate opcode
INTADDR DD 0 ; original int 2F address, updated by NB_START()
NB_INT2F ENDP
CODE ENDS ; end of segment
END ; end of program